<?PHP
namespace SDF\Lib\Account;


use SDF\Core\Model as MongoDbModel;

class CRUD extends AuthConsole {
    protected $WHERE = array();
    protected static $MongoDbModel;
    private $projection = [];
    
    public function __construct() {
        parent::__construct();
        self::$MongoDbModel = new MongoDbModel();
    }

    /**
     * 接口获取数据列表
     */
    public function get_json(){
        $page = intval($_REQUEST['page']);
        $limit = intval($_REQUEST['limit']);
        $where = $this->_where();
        $data = $this->find($where,$page,$limit,[]);
        echo json_encode($data);
    }

    /**
     * 获取数据列表
     * @param $where
     * @param $page
     * @param $page_count
     * @param $sort
     * @return array
     * @throws \Exception
     */
    private function find($where,$page,$page_count,$sort){
        if (!is_int($page) or $page < 0) {
            return array();
        }
        $skip = ($page - 1) * $page_count;
        $cursor = self::$MongoDbModel->find($where, $this->projection, $page_count, $skip, $sort);
        $count = self::$MongoDbModel->count($where);
        $data = array(
            'code' => 0,
            'msg' => "xxxxx",
            'count' => $count,
            'data' => $cursor->toArray(),
        );
        return $data;
    }

    /**
     * 删除指定id的文档
     * @param $_id
     * @throws \Exception
     */
    public function delete($_id){
        if(empty($_id)){
            $this->_error('_id不存在！');return;
        }
        $ret = self::$MongoDbModel->deleteOne(array('_id'=>MongoDbModel::format($_id)));
        if($ret->getWriteErrors()){
            $this->_error('删除失败！请联系管理员处理。');
        }else{
            //$this->_succeed('删除成功',array('callbackType'=>'closeCurrent'));//删除成功后关闭当前页面
            $this->_succeed('删除成功',array());
        }
    }

    /**
     * 显示编辑页面
     * @param $_id
     * @throws \Exception
     */
    public function edit($_id){
        if(empty($_id)){
            $this->_error('_id不存在！');return;
        }

        $data = self::$MongoDbModel->findOneById($_id);
        $this->DATA['DATA'] = (array)$data;
        //print_r($this->DATA['DATA']);exit;
        $this->display($this->DATA);
    }

    /**
     * 修改指定id的文档
     * @param $_id
     * @throws \Exception
     */
    public function update($_id){
        if(empty($_id)){
            $this->_error('_id不存在！');return;
        }

        $data = $_POST;
        if(empty($data)){
            $this->_error('data is empty ');return;
        }

        $ret = self::$MongoDbModel->updateOne(array('_id'=>self::$MongoDbModel::format($_id)),$data);
        if ($ret->getMatchedCount() > 0 or $ret->getUpsertedCount() > 0) {
            $this->_succeed("修改成功");
        }else{
            $this->_error('没有修改');
        }
    }

    /**
     * 添加数据的页面
     */
    public function add(){
        $this->display($this->DATA);
    }

    /**
     * 插入一条数据
     */
    public function insert(){
        $data = $_POST;
        if(empty($data)){
            $this->_error('empty  ');return;
        }
        $ret =  self::$MongoDbModel->insertOne($data);
        if($ret->getInsertedCount() <= 0){
            $this->_error('保存失败！请联系管理员处理。');
        }else{
            $this->_succeed('添加成功',array('callbackType'=>'closeCurrent'));
        }
    }

    /**
     * 列表页面
     * @throws \Exception
     */
    public function ls(){
        $this->DATA['sys_authority_list'] = AuthConsole::getSysAuthorityList($this->DATA['admin_user']);//获取当前用户的系统权限菜单表
        self::display($this->DATA);
    }

    /**
     * 通过 _id 修改某个字段的值
     */
    public function updateFieldValue(){
        $_id = $_REQUEST['_id'];
        $field = $_REQUEST['field'];
        $value = $_REQUEST['value'];
        $ret = self::$MongoDbModel->updateFieldValue($_id,$field,$value);
        if ($ret->getMatchedCount() > 0 or $ret->getUpsertedCount() > 0) {
            $this->_succeed("修改成功");
        }else{
            $this->_error('修改失败');
        }
    }

    /**
     * 筛选数据
     * @return array
     */
    /*public function select(){
        $where_arr = $this->_where();//对查询map加工处理
        $_REQUEST['pageNum'] = intval(@$_REQUEST['pageNum'])>0?intval(@$_REQUEST['pageNum']):1; //<!--【必须】value=1可以写死,当前第几页-->
        $_REQUEST['numPerPage'] = intval(@$_REQUEST['numPerPage'])>0?intval(@$_REQUEST['numPerPage']):20;//<!--【可选】每页显示多少条-->
        $_REQUEST['orderField'] = @$_REQUEST['orderField']?@$_REQUEST['orderField']:'_id';//<!--【可选】查询排序字段-->
        $_REQUEST['orderDirection'] = in_array(@$_REQUEST['orderDirection'],array('desc','asc'))?@$_REQUEST['orderDirection']:'desc';//<!--【可选】升序降序-->
        //todo 调用这儿的MC之前，可以先 把MC定义好。就不用重构此方法了。

        $cursor = self::$MongoDbModel->find($where_arr);
        $_REQUEST['totalCount']=  $cursor->count();
        if(empty($_REQUEST['totalCount'])){
            return array();
        }
        $cursor->sort(array(
            $_REQUEST['orderField'] => ($_REQUEST['orderDirection'] == 'asc') ?1:-1,//排序
        ));
        $cursor->skip(($_REQUEST['pageNum']-1)*$_REQUEST['numPerPage']);//跳过一些结果
        $cursor->limit($_REQUEST['numPerPage']);//限制返回结果的数量
        return $cursor;
    }*/

    /**
     * 加工搜索条件 这个方法用于实现复杂的搜索，必须被实现
     * @return array
     */
    protected function _where(){
        $where = isset($_REQUEST['where'])?$_REQUEST['where']:array();
        foreach($where as $key=>&$val){
            if($val === ''){
                unset($where[$key]);
            }
            if($key == '_id' and !is_array($val) and $val !== ''){
                $where[$key] = MongoDb::format($val);
            }
            if(is_array($val) and isset($val['$regex'])){
                if($val['$regex'] === ''){
                    unset($where[$key]);
                }else{
                    $val['$regex'] = preg_quote(trim($val['$regex']));
                }
            }
            if(is_array($val) and isset($val['$exists']) and $val['$exists'] === ''){
                if($val['$exists'] === ''){
                    unset($where[$key]);
                }else{
                    $val['$exists'] = (bool)($val['$exists']);
                }
            }
        }
        $where += $this->WHERE;
        return $where;

        /*1、比较查询
            $lt,$lte,$gt,$gte,$ne和<,<=,>,>=,!=是一一对应的，它们可以组合起来以查找一个范围内的值。
            $regex模糊匹配
        2、关联查询
            $in用于查询一个键的多个值，$nin将返回与筛选数组中所有条件都不匹配的文档。将$in与$not组合可以实现$nin相同的效果。
            $or用于对多个键做or查询。
        三、特定类型的查询
            1、null查询
            null不仅能匹配自身，还能匹配键不存在的文档。
            2、正则表达式
            3、数组查询
                $all：通过多个元素来匹配数组。
                $size：查询指定长度的数组。
                $slice：返回数组的一个子集合。
            4、内嵌文档查询
        四、$where查询
            $where查询是MongoDB的高级查询部分，可以执行任意JavaScript作为查询的一部分，是其他查询方式的一个补充。
        五、游标
            游标是很有用的东西，MongoDB数据库使用游标来返回find的执行结果。客户端使用游标可以对最终结果进行有效的控制，比如分页，排序。
        具体查询说明参考：http://www.jb51.net/article/48216.htm */
        //$where = isset($_REQUEST['where'])?$_REQUEST['where']:array();

        $where = array();
        $keywords = @$_REQUEST['keywords'];
        if(!empty($keywords)){
            $where['title']['$regex'] = $keywords;
        }
        if(isset($_REQUEST['status']) and $_REQUEST['status']>=0){//状态筛选
            $where['status'] = $_REQUEST['status'];
        }
        if(isset($_REQUEST['Y-m-d'])){//日期筛选
            $where['datetime']['$regex'] = $_REQUEST['Y-m-d'];
        }
        return $where;
    }

    /**
     * 输出http csv文件头
     * @param $filename
     */
    public static function export_csv_header( $filename=null) {
        if(empty($filename)){
            $filename = '导出文件';
        }
        $filename .= date('Ymd_His');
        header("Content-type:text/csv");
        header("Content-Disposition:attachment;filename=".$filename.'.csv');
        header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
        header('Expires:0');
        header('Pragma:public');
    }
    /**
     * 输出http excel文件头
     */
    public function export_excel_header($filename = null){
        //header("Content-type:text/csv");
        header("Content-type:application/vnd.ms-excel");
        //header("Content-Disposition:attachment;filename=订单列表.xls");
        header("Content-Disposition:attachment;filename=".$filename==null?date('导出文件Y-m-d His'):$filename.'.csv');
        header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
        header('Expires:0');
        header('Pragma:public');
    }
    /**
     * 导出CSV文件
     * @param array $headings
     * @param bool|false $rows
     * @param bool|false $filename
     * @return bool
     */
    protected static function export_csv($headings = array(), $rows = false, $filename = false) {
        if ((!empty($rows))){
            $name = ($filename !== false) ? $filename . ".csv" : "export.csv";
            header("Content-type:text/csv");
            header('Content-Disposition: attachment; filename=' . $name);
            header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
            header('Expires:0');
            header('Pragma:public');
            # Start the ouput   输出到缓冲区
            $output = fopen('php://output', 'w');//打开php缓冲
            # Create the headers    保存头信息
            fwrite($output,chr(0xEF).chr(0xBB).chr(0xBF));//用gb2312编码导出csv文档
            //print(chr(0xEF).chr(0xBB).chr(0xBF));//输出BOM头
            if(!empty($headings)) {
                fputcsv($output, $headings);
            }
            # 遍历所有行
            foreach($rows as $row){
                fputcsv($output, $row);
            }
            # 退出关闭流
            exit();
        }
        return false;
    }

    /**
     * csv文件转换为数组
     * @param string $csvfile       csv文件路径
     * @param bool $csvhead         是否读取文件头
     * @param string $delimiter     设置字段分界符（只允许一个字符）。
     * @param string $enclosure     设置字段环绕符（只允许一个字符）。
     * @param int $rowlength        必须大于 CVS 文件内最长的一行。在 PHP 5 中该参数是可选的。如果忽略（在 PHP 5.0.4 以后的版本中设为 0）该参数的话，那么长度就没有限制，不过可能会影响执行效率。
     * @return array
     */
    protected static function csv_to_array($csvfile, $csvhead = true, $delimiter=",", $enclosure='"', $rowlength=0) {
        $csvdata = array();
        if (file_exists($csvfile)) {
            $ReadHandle = @fopen($csvfile, 'r');
            $headrow = array();
            if (true === $csvhead) { $headrow = fgetcsv($ReadHandle, $rowlength, $delimiter, $enclosure); }
            while($line = fgetcsv($ReadHandle, $rowlength, $delimiter, $enclosure)) {
                if (true === $csvhead) {
                    foreach ($headrow as $key => $heading) {
                        if (!empty($heading)) { $row[trim($heading)] = (isset($line[$key])) ? $line[$key] : ''; }
                    }
                    if (!empty($row)) { $csvdata[] = $row; }
                } else {
                    if (!empty($line)) { $csvdata[] = $line; }
                }
            }
            @fclose($ReadHandle);
        }
        return $csvdata;
    }

    /**
     * 导出结果数据
     * @param bool $filename
     * @param int $numPerPage
     */
    public function export($filename = false,$numPerPage=10000){
        self::export_csv_header($filename);//输出http头
        $_REQUEST['numPerPage'] = intval($numPerPage);
        $ls = $this->select();
        //print(chr(0xEF).chr(0xBB).chr(0xBF));//输出BOM头
        $headings = array(
            '_id',
        );
        # Start the ouput   输出到缓冲区
        $output = fopen('php://output', 'w');//打开php缓冲
        fwrite($output,chr(0xEF).chr(0xBB).chr(0xBF));//用gb2312编码导出csv文档
        # Create the headers    保存头信息
        fputcsv($output, $headings);
        # 遍历所有行
        foreach($ls as $row){
            $row = array(
                $row['_id'].''
            );
            fputcsv($output, $row);
        }
        # 退出关闭流
        exit();
    }
}